package routers

import (
    "gouniapp/configs"
    "gouniapp/controllers"
	"github.com/gin-gonic/gin"
	"github.com/gin-contrib/cors"
	"github.com/didip/tollbooth/v7"
	"encoding/json"
    "html/template"
	"net/url"
	"time"
	"fmt"
	"io"
	"bytes"
	"errors"
	"strings"
)

func SetupRouter() *gin.Engine {
	// gin.SetMode(gin.ReleaseMode)    //生产模式
	router := gin.Default()
	// 设置 Gin 只信任本机的代理服务器
    router.SetTrustedProxies([]string{"127.0.0.1"})
    router.Use(cors.New(Fkz(configs.Config.GetString("server.corsOrigins"))))
    router.Static("/uploads", controllers.UploadPath)   //上传文件存储目录
    router.Static("/temp", controllers.TempPath)        //临时文件
    router.Delims("[[", "]]")                           // 使用 [[  ]] 标识符替代默认的 {{  }}，防止vue冲突
    // 添加自定义模板函数
    router.SetFuncMap(template.FuncMap{
        "toJson": func(v interface{}) template.JS {
            a, _ := json.Marshal(v)
            return template.JS(a)
        },
    })
    //手机端
    router.Static("/static", "./templates/static")
    router.Static("/assets", "./templates/assets")
    router.LoadHTMLFiles("templates/index.html", "templates/pc/pc.html", "templates/share_error.html")
    //pc端
    router.Static("/pc_static", "./templates/pc/static")
    router.Static("/pc_component", "./templates/pc/component")  //pc端子组件
    
    router.GET("/", controllers.Home)                           //默认手机端首页
    router.GET("/pc", controllers.PcHome)                       //pc端首页
    controllers.InitPermissions()                               //权限初始化                  
	v1 := router.Group("/v1")
	{
        v1.POST("laravel/create", controllers.HandleCreateRequest)              //v3系统大表导出中转服务-接收任务
        v1.GET("laravel/progress/:rediskey", controllers.HandleProgressQuery)   //v3系统大表导出中转服务-进度
        if configs.MyURL == "https://zp.kzhgzs.cn/" {
            v1.POST("/version", controllers.SourceVersionHandler)                   //检查版本更新
            v1.GET("/download/*filepath", configs.AuthMiddleware(), controllers.FileDownloadHandler)    //更新文件下载
        }
        //无需登录的路由
        v1.POST("getsession", controllers.CreateSession)            //动态密钥协商接口
        v1.POST("upload", controllers.Upload)                       //上传图片文件
        v1.POST("dbupload", controllers.UploadWithDB)               //上传图片将记录到数据库
        v1.POST("uploadvideo", controllers.UploadVideo)             //上传视频
        v1.POST("uploaddocument", controllers.UploadDocument)       //上传word模板
        v1.POST("uploadsfz", controllers.UploadSfz)                 //上传识别身份证
        v1.POST("base64toimg", controllers.Base64Toimg)             //嵌入图片表格导入时上传后端
        
        v1.POST("upload/start", controllers.StartUpload)            //分片上传
        v1.POST("upload/chunk", controllers.UploadChunk)
        v1.POST("upload/abort", controllers.UploadAbort)            //失败时清理分片
        v1.POST("upload/complete", controllers.CompleteUpload)
        v1.GET("getshare/:token", controllers.HandleShare)          //获取分享文件
        v1.POST("wxnotify", controllers.CallbackWXNotify)           //支付异步回调
        
        v1.POST("clientlogin", LimitHandler(1), controllers.Login)  //客户端专用登录，不加密
        v1.Use(DecryptRequestData())                                //解密请求数据
        v1.Use(EncryptResponseData())                               //加密响应数据
		v1.POST("register", LimitHandler(1), controllers.Register)  //注册
		v1.POST("login", LimitHandler(1), controllers.Login)        //登录
		v1.POST("qdgetconfig", controllers.Qdgetconfig)             //小程序获取全局配置
		v1.POST("maptoaddress", controllers.MaptoAddress)           //调用腾讯地图逆地理编码 API 将经纬度转换为地址
		
        // 可选登录认证路由组
        optionalAuthGroup := v1.Group("").Use(controllers.OptionalJWTMiddleware())
        {
    		optionalAuthGroup.POST("wxlogin/:code", controllers.Wxlogin)               //微信登录
    		optionalAuthGroup.POST("bindAccount", controllers.BindAccount)             //绑定用户openid
    		optionalAuthGroup.POST("index", controllers.Index)                         //首页获取查询列表
    		optionalAuthGroup.POST("getbgsx", controllers.Getbgsx)                     //从id获取项目属性
    		optionalAuthGroup.POST("getformid", LimitHandler(1), controllers.Getformid)//从项目bm和行id获取指定行数据
    		optionalAuthGroup.POST("cxjg", LimitHandler(1), controllers.Cxjg)          //查询结果
    		optionalAuthGroup.POST("dblc", LimitHandler(1), controllers.MultiTable)    //多表联查
    		optionalAuthGroup.POST("locke", controllers.Locke)                         //锁定查询
    		optionalAuthGroup.POST("qdeditrow", controllers.QdAddOreditRow)            //前端用户新建或更新行
    		optionalAuthGroup.POST("gettemplate/:id", controllers.GetTemplateDetail)   //获取指定页面模板
    		optionalAuthGroup.POST("getbloglist", controllers.GetBlogList)             //分页获取文章列表
    		optionalAuthGroup.POST("getblog/:id", controllers.GetBlogDetail)           //获取文章
    		optionalAuthGroup.POST("getldoptions", controllers.Getldoptions)           //获取联动下拉选项
    		optionalAuthGroup.POST("previewfile", controllers.PreviewFile)             //预览文件
    		optionalAuthGroup.POST("share", controllers.GenerateShareLink)             //分享文件
    		optionalAuthGroup.POST("getproducts", controllers.GetProducts)             //前台获取商品列表
    		optionalAuthGroup.POST("gethometemplate", controllers.GetHomeTemplate)     //获取首页模板
    		optionalAuthGroup.POST("parseVideoUrl", controllers.ParseVideoUrl)         //视频采集
    		optionalAuthGroup.POST("getproductdetailhome/:id", controllers.GetProductDetail)    //获取指定商品-不需要登录
    		optionalAuthGroup.POST("admin/blogformai", controllers.Blogformai)                  //AI生成文章
        }
        
		v1.Use(controllers.JWTMiddleware())                         //jwt强制登录认证中间件
		v1.POST("GetAvailableDates", controllers.GetAvailableDates) //获取可预约日期接口
		v1.POST("GetTimeSlots", controllers.GetTimeSlots)           //获取时段余量接口
		v1.POST("getproductsadmin", controllers.GetProducts)        //后台获取商品列表
		v1.POST("verifyToken", controllers.VerifyToken)             //检查登录状态
		v1.POST("getuserinfo", controllers.GetUserInfo)             //获取用户个人信息
		v1.PUT("updateprofile", controllers.UpdateUserProfile)      //前端用户更新密码和姓名、手机、邮箱
		v1.POST("addpoints", controllers.AddPoints)                 //签到获得积分
        v1.POST("getmessages", controllers.GetMessages)             //获取站内消息列表
        v1.POST("markmessageread", controllers.MarkMessageRead)     //标记消息已读
        v1.POST("getmylist", controllers.GetmyList)                 //获取我的填报记录
		//权限编辑仅管理员
        v1.POST("admin/permissions", controllers.GetPermissions)        //获取权限配置
        v1.POST("admin/savepermissions", controllers.SavePermissions)   //保存权限配置
        v1.POST("admin/getsn", controllers.GetSN)                       //获取序列号
        v1.POST("admin/plcfapi", controllers.PlcfApi)                   //批量查分POST
        v1.POST("admin/cleanapi", controllers.Cleanapi)                 //系统清理无用表
        //文件管理
        v1.POST("admin/dirfilelist", controllers.GetDirectoryList)      //获取目录树型列表
        v1.POST("admin/filelist", controllers.GetFileList)              //获取文件列表
        v1.POST("admin/directory", controllers.CreateDirectory)         //创建文件夹
        v1.POST("admin/createfile", controllers.CreateFile)             //创建文件
        v1.POST("admin/savetxt", controllers.SaveTxt)                   //保存文件
        v1.DELETE("admin/delfile", controllers.DeleteFile)              //删除文件
        v1.POST("admin/rename", controllers.RenameFile)                 //重命名文件
        v1.POST("admin/move", controllers.MoveFile)                     //移动文件
        v1.POST("admin/copy", controllers.CopyFile)                     //复制文件
        v1.POST("admin/zip", controllers.CreateZip)                     //压缩文件
        v1.POST("admin/unzip", controllers.Unzip)                       //解压文件
        
        v1.POST("getproductdetail/:id", controllers.GetProductDetail)   //获取指定商品-需要登录
        v1.POST("purchaseproduct/:id", controllers.PurchaseProduct)     //购买商品
        v1.POST("getpurchasehistory", controllers.GetPurchaseHistory)   //分页获取用户购买记录
        v1.POST("admin/getpurchases", controllers.GetPurchases)         //后台查看购买记录
        v1.POST("admin/addproducts", controllers.CreateProduct)         // 创建商品
        v1.PUT("admin/updateproducts/:id", controllers.UpdateProduct)   // 更新商品
        v1.DELETE("admin/delproducts/:id", controllers.DeleteProduct)   // 删除商品
        v1.POST("createorder", controllers.CreateOrder)                 // 统一下单接口
    	v1.POST("ispaysuccess", controllers.IspaySuccess)               // 异步判断是否成功支付
    	
        v1.POST("admin/savehometemplate", controllers.SaveHomeTemplate) // 创建或更新首页模板

		//后台路由
        adminGroup := v1.Group("/admin")
        adminGroup.Use(controllers.RBACMiddleware())
		{
		    adminGroup.POST("getbgsxlist", controllers.GetFormList)             //后台获取项目列表
            adminGroup.POST("addoreditrow", controllers.AddOreditRow)           //添加或删除行
            adminGroup.POST("delrow", controllers.DelRow)                       //删除行
		    adminGroup.POST("tablepost", controllers.Tablepost)                 //批量导入
		    adminGroup.POST("unlocke", controllers.UnLocke)                     //解锁查询
		    adminGroup.POST("gettable", controllers.GetTable)                   //分页获取表格数据
            adminGroup.POST("getformusers", controllers.GetFormUsers)           //获取全部用户id=>name列表
            adminGroup.POST("getpictemplist", controllers.GetPicTemplateList)   //分页获取证书模板列表
            adminGroup.POST("getpictemp/:id", controllers.GetPicTemplateDetail) //获取指定证书模板
            adminGroup.POST("gettemplatelist", controllers.GetTemplateList)     //分页获取页面模板列表
            adminGroup.POST("verify", controllers.VerifyReservation)            //预约核销返回信息
            adminGroup.POST("verifydo", controllers.VerifyReservationdo)        //预约核销确认

            adminGroup.POST("getimglist", controllers.GetImageList)             //获取数据库图片列表
            adminGroup.DELETE("deleteimg/:id", controllers.DeleteImage)         //删除图片
    		adminGroup.POST("addbgsx", controllers.CreateForm)                  //创建查询
            adminGroup.POST("updatebgsx", controllers.UpdateForm)               //更新查询
            adminGroup.POST("delbgsx", controllers.BatchDeleteForms)            //删除项目
            adminGroup.POST("qksj/:bm", controllers.Qksj)                       //清空全表数据
            adminGroup.POST("dcsj", controllers.OutExcel)                       //流式导出数据
            adminGroup.POST("getjd", controllers.OutExcelJd)                    //获取导出进度
            adminGroup.POST("sczs", controllers.Sczs)                           //批量生成证书
            adminGroup.POST("plscword", controllers.Plscword)                   //批量生成word
            adminGroup.POST("status/:taskid", controllers.GetTaskStatus)        //word生成进度

		    adminGroup.POST("checkupdate", controllers.CheckUpdate)             //检查更新
            adminGroup.POST("updatefiles", controllers.UpdateFiles)             //请求更新文件
            adminGroup.POST("restart", controllers.Restart)                     //更新完成请求重启后端

            adminGroup.POST("getuserlist", controllers.GetUserlist)             //分页获取用户列表
            adminGroup.POST("importuser", controllers.ImportUser)               //批量导入
            adminGroup.POST("adduser", controllers.Register)                    //添加用户
            adminGroup.POST("updateuser", controllers.UpdateUser)               //修改用户
            adminGroup.POST("deluser", controllers.DeleteUser)                  //删除用户
            
            adminGroup.POST("addtemplate", controllers.AddTemplate)             //添加页面模板
            adminGroup.PUT("updatetemplate/:id", controllers.UpdateTemplate)    //修改页面模板
            adminGroup.DELETE("deltemplate/:id", controllers.DeleteTemplate)    //删除页面模板
            
            adminGroup.POST("addpictemp", controllers.AddPicTemplate)           //添加证书模板
            adminGroup.PUT("updatepictemp/:id", controllers.UpdatePicTemplate)  //修改证书模板
            adminGroup.DELETE("deltepictemp/:id", controllers.DeletePicTemplate)//删除证书模板
            
            adminGroup.POST("getconfig", controllers.Getconfig)                 //获取配置
            adminGroup.POST("saveconfig", controllers.Saveconfig)               //保存配置
            adminGroup.POST("savemenus", controllers.SaveMenuHandler)           //保存菜单
            
            adminGroup.POST("addblog", controllers.CreateBlog)                  //添加文章
            adminGroup.PUT("updateblog/:id", controllers.UpdateBlog)            //更新文章
            adminGroup.DELETE("delblog/:id", controllers.DeleteBlog)            //删除文章
            
            adminGroup.POST("handleapproval", controllers.HandleApproval)       //审核
            adminGroup.POST("gettodoList", controllers.GetTodoList)             //获取我的流程列表
            adminGroup.POST("checkApply", controllers.CheckApply)               //是否存在进行中的流程申请
            adminGroup.POST("getProcessDetail", controllers.GetProcessDetail)   //后台查看流程详情
	    }
	}
	return router
}

// 定义自定义错误类型，包含状态码和消息
type KeyError struct {
    StatusCode int
    Message    string
}

func (e *KeyError) Error() string {
    return e.Message
}

// 公共方法：获取会话密钥
func getSessionKey(c *gin.Context) (string, error) {
    sessionID := c.GetHeader("X-Session-ID")
    if sessionID == "" {
        return "", &KeyError{StatusCode: 406, Message: "sessionID为空"}
    }
    key, found := configs.CRdb.Get("session:" + sessionID)
    if !found {
        return "", &KeyError{StatusCode: 406, Message: "会话过期或凭据错误"}
    }
    keyString, ok := key.(string)
    if !ok {
        return "", &KeyError{StatusCode: 406, Message: "凭据错误"}
    }
    return keyString, nil
}

// 中间件：解密请求数据
func DecryptRequestData() gin.HandlerFunc {
    return func(c *gin.Context) {
        body, err := io.ReadAll(c.Request.Body)
        if err != nil {
            c.JSON(500, gin.H{"error": "Failed to read request body"})
            c.Abort()
            return
        }
        key, err := getSessionKey(c)
        if err != nil {
            handleKeyError(c, err)
            return
        }
        cleanedBody := string(body)
        decData := configs.AesSimpleDecrypt(cleanedBody, string(key))
        if decData == "" {
            c.JSON(400, gin.H{"error": "Failed to decrypt data"})
            c.Abort()
            return
        }
        c.Request.Body = io.NopCloser(bytes.NewBufferString(decData))
        c.Request.ContentLength = int64(len(decData))
        c.Next()
    }
}

// 中间件：加密响应数据
func EncryptResponseData() gin.HandlerFunc {
    return func(c *gin.Context) {
        buff := &bytes.Buffer{}
        writer := &bodyWriter{
            ResponseWriter: c.Writer,
            body:           buff,
        }
        c.Writer = writer
        c.Next()
        key, err := getSessionKey(c)
        if err != nil {
            handleKeyError(c, err)
            return
        }
        encData := configs.AesSimpleEncrypt(buff.String(), key)
        c.Writer = writer.ResponseWriter
        c.Data(200, "application/json", []byte(encData))
    }
}

// 统一处理密钥相关错误
func handleKeyError(c *gin.Context, err error) {
    var keyErr *KeyError
    if errors.As(err, &keyErr) {
        c.JSON(keyErr.StatusCode, gin.H{"error": keyErr.Message})
    } else {
        c.JSON(500, gin.H{"error": "Internal server error"})
    }
    c.Abort()
}

type bodyWriter struct {
    gin.ResponseWriter
    body *bytes.Buffer
}

func (w *bodyWriter) Write(p []byte) (int, error) {
    w.body.Write(p)
    return len(p), nil
}

//中间件：限流
func LimitHandler(num float64) gin.HandlerFunc {
    lmt := tollbooth.NewLimiter(num, nil)
    return func(c *gin.Context) {
        httpError := tollbooth.LimitByRequest(lmt, c.Writer, c.Request)
        if httpError != nil {
            c.JSON(httpError.StatusCode, gin.H{"message": httpError.Message})
            c.Abort()
        } else {
            c.Next()
        }
    }
}

// 中间件：域名白名单
func Fkz(corsOrigins string) cors.Config {
    corsConfig := cors.Config{
        AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
        AllowHeaders:     []string{"Origin", "Authorization", "Content-Type"},
        ExposeHeaders:    []string{"Content-Length"},
        AllowCredentials: true,
        MaxAge:           12 * time.Hour,
    }
    if corsOrigins == "" {
        corsConfig.AllowOrigins = []string{"*"} // 如果 corsOrigins 为空，则设置允许所有来源
    } else {
        // 替换中文逗号（，）为英文逗号（,）
        corsOrigins = strings.Replace(corsOrigins, "，", ",", -1)
        originsList := strings.Split(corsOrigins, ",") // 按英文逗号分割字符串
        // 过滤掉空字符串和无效的 URL  
        validOrigins := make([]string, 0, len(originsList))
        for _, origin := range originsList {
            trimmedOrigin := strings.TrimSpace(origin)
            if trimmedOrigin != "" {
                if _, err := url.ParseRequestURI(trimmedOrigin); err == nil {
                    validOrigins = append(validOrigins, trimmedOrigin)
                } else {
                    fmt.Printf("Invalid origin: %s\n", trimmedOrigin)
                }
            }
        }
        if len(validOrigins) == 0 {
            // 如果没有有效的 URL，则可能设置允许所有来源
            corsConfig.AllowOrigins = []string{"*"}
        } else {
            corsConfig.AllowOrigins = validOrigins
        }
    }
    return corsConfig
}